/*
 * Copyright (c) 2018 LingoChamp Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.liulishuo.okdownload.sample;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.liulishuo.okdownload.DownloadContext;
import com.liulishuo.okdownload.DownloadListener;
import com.liulishuo.okdownload.DownloadTask;
import com.liulishuo.okdownload.sample.utils.DemoUtil;
import com.liulishuo.okdownload.sample.utils.LogUtil;
import com.liulishuo.okdownload.sample.utils.TagUtil;
import com.liulishuo.okdownload.core.LogUtillib;
import com.liulishuo.okdownload.core.TextUtils;
import com.liulishuo.okdownload.core.Util;
import com.liulishuo.okdownload.core.breakpoint.BreakpointInfo;
import com.liulishuo.okdownload.core.cause.EndCause;
import com.liulishuo.okdownload.core.cause.ResumeFailedCause;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Button;
import ohos.agp.components.Slider;
import ohos.agp.components.Text;
import ohos.agp.window.dialog.ToastDialog;
import ohos.app.Context;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;

/**
 * 多任务下载sample示例
 */
public class EnqueueAbility extends Ability {

    private DownloadContext downloadContext;
    private Slider slider1;
    private Slider slider2;
    private Button startDownload;
    private Text statusText1;
    private Text statusText2;
    private long slider1Value;
    private long slider2Value;
    private long contentLength1;
    private long contentLength2;

    @Override
    protected void onStart(Intent intent) {
        super.onStart(intent);
        setUIContent(ResourceTable.Layout_enqueue_ability_layout);
        slider1 = (Slider) findComponentById(ResourceTable.Id_progressBar1);
        slider2 = (Slider) findComponentById(ResourceTable.Id_progressBar2);
        startDownload = (Button) findComponentById(ResourceTable.Id_startEnqueueDownload);
        statusText1 = (Text) findComponentById(ResourceTable.Id_statusText1);
        statusText2 = (Text) findComponentById(ResourceTable.Id_statusText2);
        slider1.setProgressValue(0);
        slider1.setMinValue(0);
        slider1.setMaxValue(100);
        slider2.setProgressValue(0);
        slider2.setMinValue(0);
        slider2.setMaxValue(100);
        initTasks(this);
    }

    private void initTasks(Context context) {
        final DownloadContext.QueueSet set = new DownloadContext.QueueSet();
        final File parentFile = new File(DemoUtil.getParentFile(context), "queue");

        set.setParentPathFile(parentFile);
        set.setMinIntervalMillisCallbackProcess(200);
        final DownloadContext.Builder builder = set.commit();

        String url = "https://cdn.llscdn.com/yy/files/tkzpx40x-lls-LLS-5.7-785-20171108-111118.apk";
        DownloadTask boundTask = builder.bind(url);
        TagUtil.saveTaskName(boundTask, "2. LiuLiShuo");

        url = "https://t.alipayobjects.com/L1/71/100/and/alipay_wap_main.apk";
        boundTask = builder.bind(url);
        TagUtil.saveTaskName(boundTask, "3. Alipay");

        this.downloadContext = builder.build();
        startDownload.setClickedListener(component -> {
            if (downloadContext.isStarted()) {
                downloadContext.stop();
            } else {
                startDownloadContext();
            }
        });
    }

    private void startDownloadContext() {
        downloadContext.start(new DownloadListener() {
            @Override
            public void taskStart(@NonNull DownloadTask task) {
                taskStartInit(task);
            }

            @Override
            public void connectTrialStart(@NonNull DownloadTask task, @NonNull Map<String, List<String>> requestHeaderFields) {
            }

            @Override
            public void connectTrialEnd(@NonNull DownloadTask task, int responseCode, @NonNull Map<String, List<String>> responseHeaderFields) {
            }

            @Override
            public void downloadFromBeginning(@NonNull DownloadTask task, @NonNull BreakpointInfo info, @NonNull ResumeFailedCause cause) {
            }

            @Override
            public void downloadFromBreakpoint(@NonNull DownloadTask task, @NonNull BreakpointInfo info) {
            }

            @Override
            public void connectStart(@NonNull DownloadTask task, int blockIndex, @NonNull Map<String, List<String>> requestHeaderFields) {
            }

            @Override
            public void connectEnd(@NonNull DownloadTask task, int blockIndex, int responseCode, @NonNull Map<String, List<String>> responseHeaderFields) {
            }

            @Override
            public void fetchStart(@NonNull DownloadTask task, int blockIndex, long contentLength) {
                fetchStartInit(task, contentLength);
            }

            @Override
            public void fetchProgress(@NonNull DownloadTask task, int blockIndex, long increaseBytes) {
                taskProgressInfoPrint(task, increaseBytes);
            }

            @Override
            public void fetchEnd(@NonNull DownloadTask task, int blockIndex, long contentLength) {
            }

            @Override
            public void taskEnd(@NonNull DownloadTask task, @NonNull EndCause cause, @Nullable Exception realCause) {
                taskEndInfoPrint(task, cause);
            }
        }, false);
    }

    private void taskStartInit(DownloadTask task) {
        final Optional<String> taskName = (Optional<String>) task.getTag(3);
        if ("2. LiuLiShuo".equals(taskName.orElse(null))) {
            statusText1.setText(" isStarted...");
        } else if ("3. Alipay".equals(taskName.orElse(null))) {
            statusText2.setText(" isStarted...");
        }
    }

    private void fetchStartInit(DownloadTask task, long contentLength) {
        final Optional<String> taskName = (Optional<String>) task.getTag(3);
        if ("2. LiuLiShuo".equals(taskName.orElse(null))) {
            contentLength1 = contentLength;
        } else if ("3. Alipay".equals(taskName.orElse(null))) {
            contentLength2 = contentLength;
        }
    }

    private void taskProgressInfoPrint(DownloadTask task, long increaseBytes) {
        final Optional<String> taskName = (Optional<String>) task.getTag(3);
        if ("2. LiuLiShuo".equals(taskName.orElse(null))) {
            slider1Value += increaseBytes;
            int percent = (int) (slider1Value * 1.0f / contentLength1 * 100f);
            slider1.setProgressValue(percent);
            statusText1.setText("LiuLiShuo app" + " is download " + Util.humanReadableBytes(increaseBytes, true) + "/s(" + percent + "%)");
        } else if ("3. Alipay".equals(taskName.orElse(null))) {
            slider2Value += increaseBytes;
            int percent = (int) (slider2Value * 1.0f / contentLength2 * 100f);
            slider2.setProgressValue(percent);
            statusText2.setText("Alipay app" + " is download " + Util.humanReadableBytes(increaseBytes, true) + "/s(" + percent + "%)");
        }
    }

    private void taskEndInfoPrint(DownloadTask task, EndCause cause) {
        final Optional<String> taskName = (Optional<String>) task.getTag(3);
        if ("2. LiuLiShuo".equals(taskName.orElse(null))) {
            final String realMd5 = getFileSHA256(task.getFile());
            LogUtillib.e("zzhs_00699_", "SHA-256-----" + realMd5);
            if (cause == EndCause.COMPLETED) {
                if (!TextUtils.isEmpty(realMd5) && "ad90dd22875dc4dbdf511f701b9a2ab0f08b38193563fda9d607ed8bfc07e4ac".equals(realMd5.toLowerCase(Locale.ROOT))) {
                    LogUtillib.e("zzhs_00700_", "file download success!!!!");
                    ToastDialog dialog = new ToastDialog(getContext());
                    dialog.setText("file download success!");
                    dialog.show();
                }
            }

        } else if ("3. Alipay".equals(taskName.orElse(null))) {
            final String realMd5 = getFileSHA256(task.getFile());
            LogUtillib.e("zzhs_00701_", "SHA-256-----" + realMd5);
            if (cause == EndCause.COMPLETED) {
                if (!TextUtils.isEmpty(realMd5) && "2b44cd3b42f5fd867a50b703298e8bb72fcedc16613299f5e8a867432f287a9c".equals(realMd5.toLowerCase(Locale.ROOT))) {
                    LogUtillib.e("zzhs_00702_", "file download success!!!!");
                }
            }
        }
    }

    /**
     * 计算文件 SHA256
     *
     * @param file 文件
     * @return 返回文件的SHA256字符串，如果计算过程中任务的状态变为取消或暂停，返回null， 如果有其他异常，返回空字符串
     */
    private static String getFileSHA256(File file) {
        try (InputStream stream = Files.newInputStream(file.toPath(), StandardOpenOption.READ)) {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] buf = new byte[8192];
            int len;
            while ((len = stream.read(buf)) > 0) {
                digest.update(buf, 0, len);
            }
            return toHexString(digest.digest());
        } catch (IOException | NoSuchAlgorithmException e) {
            LogUtil.error("enqueue", e.getMessage());
            return null;
        }
    }

    private static final char[] HEX_CODE = "0123456789ABCDEF".toCharArray();

    private static String toHexString(byte[] data) {
        StringBuilder stringBuilder = new StringBuilder(data.length * 2);
        for (byte byt : data) {
            stringBuilder.append(HEX_CODE[(byt >> 4) & 0xF]);
            stringBuilder.append(HEX_CODE[(byt & 0xF)]);
        }
        return stringBuilder.toString();
    }
}
